iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 18
1
自我挑戰組

Laravel 實戰經驗分享系列 第 18

Laravel 實戰經驗分享 - Day18 JWT 實作

  • 分享至 

  • xImage
  •  

今天我們來將前兩天提到的 JWT 實作出來,並以 Day15 的 RESTful API 實作方式互相結合,以 API 的方式實作 JWT 的認證。

將 JWT 安裝進 Laravel 環境中

  • 首先,透過 composer 將 JWT 套件 tymon/jwt-auth 引用進來(建議版本在 1.0 以上)
composer require tymon/jwt-auth 
  • config/app.php 內新增 Service Provider
'providers' => [

    ...

    Tymon\JWTAuth\Providers\LaravelServiceProvider::class,
]
  • 並且 Publish config,該指令會自動將剛剛安裝的套件設定放在 config/jwt.php
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
  • 建立密鑰,該密鑰會儲存於 .env 中 JWT_SECRET = "foo"
php artisan jwt:secret

使用方法

  • 更新 User Model,打開 app/Models/User.php
    • 首先需要 implement Tymon\JWTAuth\Contracts\JWTSubject
    • 並且實作兩個 functions,分別為 getJWTIdentifier() 以及 getJWTCustomerClaims()
namespace App;

...
use Illuminate\Foundation\Auth\User as Authenticatable;
use Tymon\JWTAuth\Contracts\JWTSubject;

class User extends Authenticatable implements JWTSubject
{

...

    public function getJWTIdentifier()
    {
        return $this->getKey();
    }
    public function getJWTCustomClaims()
    {
        return[];
    }

...

}
  • 設定 Auth Guard(該方法僅適用於 Laravel 5.2 後)
    • config/auth.php 內更改認證方式,將 guard 的認證方式改為 api,api 的 driver 改為 jwt,程式碼如下
'defaults' => [
    'guard' => 'api',
    'passwords' => 'users',
],

...

'guards' => [
    'api' => [
        'driver' => 'jwt',
        'provider' => 'users',
    ],
],
  • 新增認證的 Routes,打開 routes/api.php
Route::group([
    'prefix' => 'auth'
], function ($router) {
		Route::post('login', [AuthController::class,'login']);
		Route::post('logout', [AuthController::class,'logout']);
		Route::post('refresh', [AuthController::class,'refresh']);
		Route::post('me', [AuthController::class,'me']);
});
  • 建立 AuthController
php artisan make:controller AuthController
  • 程式碼如下
<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;

class AuthController extends Controller
{
    /**
     * Create a new AuthController instance
     * 
     * @return void
     */
    public function __construct()
    {
        $this->middleware('auth:api', ['except' => ['login']]);
    }
    /**
     * Get a JWT via given credentials.
     * 
     * @return \Illuminate\Http\JsonResponse
     */
    public function login()
    {
        $credentials = request(['email', 'password']);
        if (!$token = Auth::guard()->attempt($credentials)) {
            return response()->json(['error' => 'Unauthorize'], 401);
        }
        return $this->respondWithToken($token);
    }
    /**
     * Get a authenticated User.
     * 
     * @return \Illuminate\Http\JsonResponse
     */
    public function me()
    {
        return response()->json(Auth::guard()->user());
    }
    /**
     * Log the user out(Invalidate the Token).
     * 
     * @return \Illuminate\Http\JsonResponse
     */
    
    public function logout()
    {
        Auth::guard()->logout();
        return response()->json(['message'=>'Successfully logged out']);
    }
    /**
     * Refresh a Token.
     * 
     * @return \Illuminate\Http\JsonResponse
     */
    public function refresh()
    {
        return $this->respondWithToken(Auth::guard()->refresh());
    }
    protected function respondWithToken($token)
    {
        return response()->json([
            'access_token'=>$token,
            'token_type'=>'bearer',
            'expires_in'=>Auth::guard()->factory()->getTTL()*60
        ]);
    }
}
  • 此時就可以使用 Postman 來測試 API,以下是先前新增的測試帳號,GET localhost:8000/api/users

  • POST localhost/api/auth/login 並在 body 加入設定好的 email、password,在 Headers 中加入 Content-Type: application/json,即可拿到一串 access token,依照昨天所說的 JWT 設計規範,我們這邊的實作是直接使用 refresh token 作為 access token

  • 若是 token 過期,則系統會回傳 401 的 HTTP 狀態


以上就是 JWT 的實作囉,不過實際應用狀況會根據各種系統的設計以及業務邏輯有不同微調,依我之前的經驗,通常系統剛開始設計時,登入流程就會有很多不同的做法,考驗前後端的相互配合。


上一篇
Laravel 實戰經驗分享 - Day17 JWT 概念分享(下)
下一篇
Laravel 實戰經驗分享 - Day19 PHPUnit 如何在你的 Laravel 專案中寫測試
系列文
Laravel 實戰經驗分享30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言